1 Find regions with high covariances in each population

  • From Temporal Covariance analysis -output covariances for each time period

1.1 Plot the covariances across the genome

#Find the regions with a high temporal covariance 
pops<-c("PWS","TB","SS")
winsize<-c("50k","100k","250k")
evens<-paste0("chr",seq(2,26, by=2))
cov.list<-list()
covs_all<-list()
k=1
for (p in 2: length(pops)){
    pop<-pops[p]
    for (i in 1: length(winsize)){
        iv<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/MD7000_3pops_intervals_",winsize[i],"window.csv"), row.names = 1)
        if (p==3) {
            cov23<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/",pop,"_cov23_2017-2006_2006-1996_md7000_",winsize[i],"window.csv"), header = F)
            covs<-cbind(iv, cov23)
            colnames(covs)[4]<-c("cov23")
            covs$index=1:nrow(covs)
            covs$color<-"col1"
            covs$color[covs$chrom %in% evens]<-"col2"
    
            covs[sapply(covs, is.infinite)] <- NA
            covs[sapply(covs, is.nan)] <- NA
            
            cov.list[[k]]<-covs
            names(cov.list)[k]<-paste0(pop,"_",winsize[i])    
            k=k+1
            
            y<-min(covs$cov23, na.rm=T)
            ymin<-ifelse (y<=-0.1,-0.1, y) 
            ymax<-max(covs$cov23, na.rm=T)
            ggplot(covs, aes(x=index, y=cov23, color=color))+
                geom_point(size=1, alpha=0.5)+
                theme_classic()+
                ylim(ymin,ymax)+
                scale_color_manual(values=c("gray70","steelblue"), guide="none")+
                ylab("Covariance")+xlab('Chromosome')+
                theme(axis.text.x = element_blank())+
                ggtitle(paste0(pop," ", winsize[i]," window"))
            ggsave(paste0("../Output/COV/",pop,"_tempCovs_acrossGenome_",winsize[i], "Window.png"), width = 8, height = 2.7, dpi=300) 
        }
        else {
            cov12<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/",pop,"_cov12_1996-1991_2006-1996_md7000_",winsize[i],"window.csv"), header = F)
            cov23<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/",pop,"_cov23_2017-2006_2006-1996_md7000_",winsize[i],"window.csv"), header = F)
            cov13<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/",pop,"_cov13_2017-2006_1996-1991_md7000_",winsize[i],"window.csv"), header = F)
            covs<-cbind(iv, cov12, cov23,cov13)
            colnames(covs)[4:6]<-c("cov12","cov23","cov13")
            covs$index=1:nrow(covs)
    
            covs$color<-"col1"
            covs$color[covs$chrom %in% evens]<-"col2"
    
            covs[sapply(covs, is.infinite)] <- NA
            covs[sapply(covs, is.nan)] <- NA
            
            cov.list[[k]]<-covs
            names(cov.list)[k]<-paste0(pop,"_",winsize[i])    
            k=k+1
            covsm<-melt(covs[,c("index","color","cov12","cov23","cov13")], id.vars = c("index", "color"))
            ymax<-max(covsm$value, na.rm=T)
            y<-min(covsm$value, na.rm=T)
            ymin<-ifelse (y<=-0.1,-0.1, y) 
            ggplot(covsm, aes(x=index, y=value, color=color))+
                facet_wrap(~variable, nrow=3)+
                geom_point(size=1, alpha=0.5)+
                theme_classic()+
                ylim(ymin,ymax)+
                scale_color_manual(values=c("gray70","steelblue"), guide="none")+
                ylab("Covariance")+xlab('Chromosome')+
                theme(axis.text.x = element_blank())+
                ggtitle(paste0(pop," ", winsize[i]," window"))
            ggsave(paste0("../Output/COV/",pop,"_tempCovs_acrossGenome_",winsize[i], "Window.png"), width = 8, height = 8, dpi=300)    
        }
    }
    
}

1.2 Find the outlier regions for each time period

#find how outliers overlap between different windows
cov12<-data.frame()
cov23<-data.frame()
cov13<-data.frame()

for (i in 1:length(cov.list)){
 if (grepl("PWS",names(cov.list)[i])|grepl("TB",names(cov.list)[i])){
    covs<-cov.list[[i]]
    
    pop<-gsub("_.+",'', names(cov.list)[i])
    win<-gsub(paste0(pop,"_"), '', names(cov.list)[i])
    
    covs<-covs[order(covs$cov12, decreasing=T),]
    n<-ceiling(nrow(covs)*0.01) #top1% region
    covs12_top<-covs[1:n,c(1:4)]
    covs12_top<-covs12_top[order(covs12_top$chrom, covs12_top$start),]
    covs12_top$window<-win
    covs12_top$pop<-pop
    cov12<-rbind(cov12, covs12_top)
    
    covs<-covs[order(covs$cov13, decreasing=T),]
    n<-ceiling(nrow(covs)*0.01) #top1% region
    covs13_top<-covs[1:n,c(1:3,6)]
    covs13_top<-covs13_top[order(covs13_top$chrom, covs13_top$start),]
    covs13_top$window<-win
    covs13_top$pop<-pop
    cov13<-rbind(cov13, covs13_top)
    
    covs<-covs[order(covs$cov23, decreasing=T),]
    n<-ceiling(nrow(covs)*0.01) #top1% region
    covs23_top<-covs[1:n,c(1:3,5)]
    covs23_top<-covs23_top[order(covs23_top$chrom, covs23_top$start),]
    covs23_top$window<-win
    covs23_top$pop<-pop
    cov23<-rbind(cov23, covs23_top)
 }
 if (grepl("SS",names(cov.list)[i])){
    covs<-cov.list[[i]]
    
    pop<-gsub("_.+",'', names(cov.list)[i])
    win<-gsub(paste0(pop,"_"), '', names(cov.list)[i])
    
    covs<-covs[order(covs$cov23, decreasing=T),]
    n<-ceiling(nrow(covs)*0.01) #top1% region
    covs23_top<-covs[1:n,c(1:4)]
    covs23_top<-covs23_top[order(covs23_top$chrom, covs23_top$start),]
    covs23_top$window<-win
    covs23_top$pop<-pop
    cov23<-rbind(cov23, covs23_top)
    
    }
}


write.csv(cov12, "../Output/COV/3pops_top1percent_outlier_regions.cov12.csv",row.names = F)
write.csv(cov23, "../Output/COV/3pops_top1percent_outlier_regions.cov23.csv",row.names = F)
write.csv(cov13, "../Output/COV/3pops_top1percent_outlier_regions.cov13.csv",row.names = F)
#Create plots with different colors for outliers
#for COV12 and COV13 for TB and PWS (100K)
cv<-c("cov12","cov13","cov23")
winsize<-c("50k","100k","250k")

for (i in 1:length(cv)){
    if (i==1|i==2){
        for (w in 1: length(winsize)){
            #PWS
            df1<-cov.list[[paste0("PWS_", winsize[w])]]
            df1<-df1[order(df1[,cv[i]], decreasing=T),]
            n<-ceiling(nrow(df1)*0.01) #top1% region
            df1$top1<-"N"
            df1$top1[1:n]<-"PWS"
            
            #tb
            df2<-cov.list[[paste0("TB_", winsize[w])]]
            df2<-df2[order(df2[,cv[i]], decreasing=T),]
            df2$top1<-"N"
            df2$top1[1:n]<-"TB"
            
            co<-rbind(df1, df2)
    
            co$chrom<-factor(co$chrom, levels=paste0("chr", 1:26))
            co$top1<-factor(co$top1, levels=c("PWS","TB","N"))
            colnames(co)[which(colnames(co)==cv[i])]<-"cov"
    
            ymax<-max(co$cov, na.rm=T)
            ggplot(co, aes(x=start/1000000, y=cov, color=top1))+
                geom_point(size=0.5)+
                facet_wrap(~chrom, ncol=4)+
                theme_classic()+ylim(-0.1,ymax)+
                scale_color_manual(values=c("deeppink","orange" ,"#ADD8E680"), labels=c("PWS", "TB", ""))+
                ylab("Covariance")+xlab('Postion (Mb)')+
                ggtitle(paste0(winsize[w]," window ",cv[i]))+
                scale_x_continuous(labels = comma)+
                guides(color = guide_legend(override.aes = list(color=c("deeppink","orange","white")), title=element_text("Top 1%")))
   
                ggsave(paste0("../Output/COV/COVscan/",cv[i],"_perChrom_",winsize[w], "Window_Outliers.png"), width = 10, height = 8, dpi=300)
        }
       
    }
   
    if (i==3){
        for (w in 1: length(winsize)){
        #pws
        df1<-cov.list[[paste0("PWS_", winsize[w])]]
        df1<-df1[,c("chrom","start","end","cov23")]
        df1<-df1[order(df1$cov23, decreasing=T),]
        n<-ceiling(nrow(df1)*0.01) #top1% region
        df1$top1<-"N"
        df1$top1[1:n]<-"PWS"
    
        #tb
        df2<-cov.list[[paste0("TB_", winsize[w])]]
        df2<-df2[,c("chrom","start","end","cov23")]
        df2<-df2[order(df2$cov23, decreasing=T),]
        df2$top1<-"N"
        df2$top1[1:n]<-"TB"
    
        #ss
        df3<-cov.list[[paste0("SS_", winsize[w])]]
        df3<-df3[,c("chrom","start","end","cov23")]
        df3<-df3[order(df3$cov23, decreasing=T),]
        df3$top1<-"N"
        df3$top1[1:n]<-"SS"

        co<-rbind(df1,df2,df3)

        co$chrom<-factor(co$chrom, levels=paste0("chr", 1:26))
        co$top1<-factor(co$top1, levels=c("PWS","TB","SS","N"))
        ymax<-max(co$cov23, na.rm=T)
        ggplot(co, aes(x=start/1000000, y=cov23, color=top1))+
            geom_point(size=0.5)+
            facet_wrap(~chrom, ncol=4)+
            theme_classic()+ylim(-0.1,ymax)+
            ylab("Covariance")+xlab('Postion (Mb)')+
            ggtitle(paste0(winsize[w]," window ",cv[i]))+
            scale_x_continuous(labels = comma)+
            #scale_color_discrete(breaks=c("PWS","SS","TB"))+
            scale_color_manual(values=c("deeppink","orange",gre,"#ADD8E666"), labels=c("PWS","TB","SS", ""))+
            guides(color = guide_legend(override.aes = list(color=c("deeppink","orange",gre,         "white")),title=element_text("Top 1% outliers"))) 
        ggsave(paste0("../Output/COV/COVscan/COV23_3Pops_perChrom_",winsize[w], "Window_Outliers.png"), width = 10, height = 9, dpi=300)
        }
    }
    
}


1.3 Run the snpEff pipeline to find annotation in the outlier regions

  • Create a script to run SnpEff

Create VCF files with selected regions & run snpEff

#Create bed files
cv<-c("cov12","cov13","cov23")

for (i in 1:3){
    df<-read.csv(paste0("../Output/COV/3pops_top1percent_outlier_regions.",cv[i],".csv"))
    dfp<-df[df$pop=="PWS",]
    write.table(dfp[,1:3], paste0("../Output/COV/COVscan/PWS_outliers_",cv[i],".bed"),quote = F, row.names = F, col.names = F,sep = "\t")
    dft<-df[df$pop=="TB",]
    write.table(dft[,1:3], paste0("../Output/COV/COVscan/TB_outliers_",cv[i],".bed"),quote = F, row.names = F, col.names = F,sep = "\t")
    
    if (i==3){
        dfs<-df[df$pop=="SS",]
        write.table(dfs[,1:3], paste0("../Output/COV/COVscan/SS_outliers_",cv[i],".bed"),quote = F, row.names = F, col.names = F,sep = "\t")
        
    }
}


#create a bash script to run snpEff
bedfiles<-list.files("../Output/COV/COVscan/", pattern="*.bed")

sink("../COVscan_createVCFs.sh")
cat("#!/bin/bash \n\n")
for (i in 1:length(bedfiles)){
    fname<-gsub(".bed",'', bedfiles[i])
    cat(paste0("vcftools --gzvcf Data/new_vcf/PH_DP600_7000_minQ20_minMQ30_NS0.5_maf05.vcf.gz --bed Output/COV/COVscan/", bedfiles[i], " --out Output/COV/COVscan/", fname," --recode --keep-INFO-all \n"))
}
sink(NULL)  

#create a bash script to run snpEff
vfiles<-list.files("../Output/COV/COVscan/", pattern=".recode.vcf")

sink("~/programs/snpEff/runsnpEff_cov.sh")
cat("#!/bin/bash \n\n")
for (i in 1:length(vfiles)){
    fname<-gsub(".recode.vcf","",vfiles[i])
    cat(paste0("java -Xmx8g -jar snpEff.jar Ch_v2.0.2.99 ~/Projects/PacHerring/Output/COV/COVscan/",vfiles[i], " -stats ~/Projects/PacHerring/Output/COV/COVscan/",fname,".html >  ~/Projects/PacHerring/Output/COV/COVscan/Anno.",fname,".vcf \n"))
    
    #extract the annotation information
    cat(paste0("bcftools query -f '%CHROM %POS %INFO/AF %INFO/ANN\\n' ~/Projects/PacHerring/Output/COV/COVscan/Anno.",fname,".vcf > ~/Projects/PacHerring/Output/COV/COVscan/",fname,"_annotation \n\n"))

}
sink(NULL)  

1.3.1 Create summary gene files from snpEff and check overlapping genes.

## Create summary files of snpEff results (gene annotations in the regions of interest) and reformat as a ShinyGo input 

#create gene list 
gfiles<-list.files("../Output/COV/COVscan/", pattern="genes.txt")

for (i in 1:length(gfiles)){
    df<-read.table(paste0("../Output/COV/COVscan/",gfiles[i]), sep="\t")
    df<-df[,1:7]
    colnames(df)<-c("GeneName","GeneId","TranscriptId","BioType","variants_impact_HIGH","variants_impact_LOW",  "variants_impact_MODERATE")
    
    fname<-gsub(".genes.txt","",gfiles[i])
    genes<-unique(df$GeneId)
    sink(paste0("../Output/COV/COVscan/geneIDlist_",fname,".txt"))
    cat(paste0(genes,"; "))
    sink(NULL)
}

# Find the intersecting gene names across populations

gfiles2<-list.files("../Output/COV/COVscan/", pattern="geneIDlist")
glist<-list()
for (i in 1:length(gfiles)){
    df<-read.table(paste0("../Output/COV/COVscan/",gfiles2[i]), sep=";")
    df<-t(df)
    df<-gsub(" ","",df)
    df2<-df[!is.na(df)]
    vname<-gsub(".txt","",gfiles2[i],)
    vname<-gsub("geneIDlist_","", vname)
    glist[[i]]<-df2
    names(glist)[i]<-vname
}

times<-c("cov12","cov13","cov23")
common<-list()
common_genes<-data.frame(time=times)
for (i in 1:2){
    tlist<-glist[grep(times[i], names(glist))]
    if (i !=3){
        common[[i]]<-intersect(tlist[[1]], tlist[[2]])
        names(common)[[i]]<-times[i]
        common_genes$PWS[i]<-length(tlist[[grep("PWS", names(tlist))]])
        common_genes$TB[i]<-length(tlist[[grep("TB", names(tlist))]])
        common_genes$SS[i]<-NA
        common_genes$common_PWS.TB[i]<-length(intersect(tlist[[1]], tlist[[2]]))
    }
    if (i==3){
        common_genes$PWS[i]<-length(tlist[[grep("PWS", names(tlist))]])
        common_genes$TB[i]<-length(tlist[[grep("TB", names(tlist))]])
        common_genes$SS[i]<-length(tlist[[grep("SS", names(tlist))]])
        common_genes$common_PWS.TB[i]<-length(intersect(tlist[[1]], tlist[[3]]))
        common_genes$common_PWS.SS[i]<-length(intersect(tlist[[1]], tlist[[2]]))
        common_genes$common_SS.TB[i]<-length(intersect(tlist[[2]], tlist[[3]]))
        common_genes$common3[i]<-length(intersect(tlist[[1]],intersect(tlist[[2]], tlist[[3]])))
        k=i
        common[[k]]<-intersect(tlist[[1]], tlist[[2]])
        names(common)[[k]]<-paste0(times[i],"_PWS.SS")
        k=k+1
        common[[k]]<-intersect(tlist[[1]], tlist[[3]])
        names(common)[[k]]<-paste0(times[i],"_PWS.TB")
        k=k+1
        common[[k]]<-intersect(tlist[[2]], tlist[[3]])
        names(common)[[k]]<-paste0(times[i],"_SS.TB")
        k=k+1
        common[[k]]<-intersect(tlist[[1]],intersect(tlist[[2]], tlist[[3]]))
        names(common)[[k]]<-paste0(times[i],"_3pops")
        }
    }
}
    
write.csv(common_genes, "../Output/COV/COVscan/Common_genes_3pops.csv")

#What are the overlapping gene names

#aggregate all gene names
Genes<-data.frame()
for (i in 1:length(gfiles)){
    df<-read.table(paste0("../Output/COV/COVscan/",gfiles[i]), sep="\t")
    df<-df[,1:2]
    colnames(df)<-c("GeneName","GeneId")
    df<-df[!duplicated(df),]
    Genes<-rbind(Genes, df)
    Genes<-Genes[!duplicated(Genes),]
}

for (i in 1: length(common)){
    gids<-common[[i]]
    df<-data.frame(GeneId=gids)
    
    df<-merge(df, Genes, by="GeneId")
    write.csv(df, paste0("../Output/COV/COVscan/Common_genes_", names(common)[i],".csv"), row.names = F)
    
}

1.3.1.1 Overlapping gene numbers

time PWS TB SS common_PWS.TB common_PWS.SS common_SS.TB common3
cov12 292 338 NA 30 NA NA NA
cov13 311 292 NA 23 NA NA NA
cov23 270 336 227 49 22 19 4

1.3.1.2 Overlapping regions

# Find the overlapping regions where the 4 genes belong to:
cov23_all<-read.csv("../Output/COV/3pops_top1percent_outlier_regions.cov23.csv")
cov23_all<-cov23_all[cov23_all$window=="100k",]
pws<-cov23_all[cov23_all$pop=="PWS",]
tb<-cov23_all[cov23_all$pop=="TB",]
ss<-cov23_all[cov23_all$pop=="SS",]

#Overlap between PWS and TB
pws$id<-paste0(pws$chrom,"_",pws$start)
tb$id<-paste0(tb$chrom,"_",tb$start)
ss$id<-paste0(ss$chrom,"_",ss$start)
intersect(pws$id, tb$id) 
#[1] "chr13_29200000" "chr16_6400000"  "chr16_26800000" "chr18_2800000"  "chr18_12700000" "chr20_7500000" 
#[7] "chr5_13400000"  "chr9_25600000" 
#8 regions exactly match

intersect(pws$id, ss$id) 
# "chr10_10900000" "chr12_28500000" "chr18_2800000"  "chr25_1100000"  "chr3_20200000"  "chr4_31000000" 

intersect(tb$id, ss$id) 
#"chr13_22800000" "chr14_3300000"  "chr17_9700000"  "chr18_2800000"  "chr2_900000"   

intersect(pws$id, intersect(ss$id, tb$id))
#chr18_2800000"


#### Check chromosome region overlap +-100,000 bases

overlps<-data.frame()
overlps2<-data.frame()
for (i in 1: nrow(pws)){
    re2<-tb[tb$chrom==pws$chrom[i],]
    if (nrow(re2)>=1){
        for (j in 1: nrow(re2)){
            if (re2$start[j]<=pws$start[i]+100000 & re2$start[j]>=pws$start[i]-100000){
                overlps<-rbind(overlps, re2[j,])
                overlps2<-rbind(overlps2,pws[i,])}
    }}
}      


#Overlapping windows:
ov<-data.frame(id=overlps$id)
for (i in 1: nrow(overlps)){
    if (overlps$start[i]<overlps2$start[i]) {ov$start[i]<-overlps$start[i]; ov$end[i]<-overlps2$end[i]}
    if (overlps$start[i]>=overlps2$start[i]) {ov$start[i]<-overlps2$start[i];ov$end[i]<-overlps$end[i]}
}
write.csv(ov, "../Output/COV/COVscan/Overlap_regions_COV23_PWS.TB_plusminus100k.csv", row.names = F)


#### Check chromosome region overlap +-200,000 bases
overlps<-data.frame()
overlps2<-data.frame()
for (i in 1: nrow(pws)){
    re2<-tb[tb$chrom==pws$chrom[i],]
    if (nrow(re2)>=1){
        for (j in 1: nrow(re2)){
            if (re2$start[j]<=pws$start[i]+200000 & re2$start[j]>=pws$start[i]-200000){
                overlps<-rbind(overlps, re2[j,])
                overlps2<-rbind(overlps2,pws[i,])}
    }}
}      

#Overlapping windows:
ov<-data.frame(id=overlps$id)
for (i in 1: nrow(overlps)){
    if (overlps$start[i]<overlps2$start[i]) {ov$start[i]<-overlps$start[i]; ov$end[i]<-overlps2$end[i]}
    if (overlps$start[i]>=overlps2$start[i]) {ov$start[i]<-overlps2$start[i];ov$end[i]<-overlps$end[i]}
}
write.csv(ov, "../Output/COV/COVscan/Overlap_regions_COV23_PWS.TBplusminus200k.csv", row.names = F)

## PWS and SS
#### Check chromosome region overlap +-200,000 bases
overlps<-data.frame()
overlps2<-data.frame()
for (i in 1: nrow(pws)){
    re2<-ss[ss$chrom==pws$chrom[i],]
    if (nrow(re2)>=1){
        for (j in 1: nrow(re2)){
            if (re2$start[j]<=pws$start[i]+200000 & re2$start[j]>=pws$start[i]-200000){
                overlps<-rbind(overlps, re2[j,])
                overlps2<-rbind(overlps2,pws[i,])}
    }}
}      

#Overlapping windows:
ov<-data.frame(id=overlps$id)
for (i in 1: nrow(overlps)){
    if (overlps$start[i]<overlps2$start[i]) {ov$start[i]<-overlps$start[i]; ov$end[i]<-overlps2$end[i]}
    if (overlps$start[i]>=overlps2$start[i]) {ov$start[i]<-overlps2$start[i];ov$end[i]<-overlps$end[i]}
}
write.csv(ov, "../Output/COV/COVscan/Overlap_regions_COV23_PWS.SSplusminus200k.csv", row.names = F)

## SS and TB
#### Check chromosome region overlap +-200,000 bases
overlps<-data.frame()
overlps2<-data.frame()
for (i in 1: nrow(pws)){
    re2<-ss[ss$chrom==tb$chrom[i],]
    if (nrow(re2)>=1){
        for (j in 1: nrow(re2)){
            if (re2$start[j]<=tb$start[i]+200000 & re2$start[j]>=tb$start[i]-200000){
                overlps<-rbind(overlps, re2[j,])
                overlps2<-rbind(overlps2,tb[i,])}
    }}
}      
#Overlapping windows:
ov<-data.frame(id=overlps$id)
for (i in 1: nrow(overlps)){
    if (overlps$start[i]<overlps2$start[i]) {ov$start[i]<-overlps$start[i]; ov$end[i]<-overlps2$end[i]}
    if (overlps$start[i]>=overlps2$start[i]) {ov$start[i]<-overlps2$start[i];ov$end[i]<-overlps$end[i]}
}
write.csv(ov, "../Output/COV/COVscan/Overlap_regions_COV23_SS.TBplusminus200k.csv", row.names = F)


## PWS, SS and TB
#### Check chromosome region overlap +-200,000 bases
overlppw<-data.frame()
overlpss<-data.frame()
overlptb<-data.frame()
for (i in 1: nrow(pws)){
    re2<-ss[ss$chrom==pws$chrom[i],]
    re3<-tb[tb$chrom==pws$chrom[i],]
    
    if (nrow(re2)>=1& nrow(re3)>=1){
        for (j in 1: nrow(re2)){
            if (re2$start[j]<=pws$start[i]+200000 & re2$start[j]>=pws$start[i]-200000){
                for (k in 1: nrow(re3)){
                    if (re3$start[k]<=pws$start[i]+200000 & re3$start[k]>=pws$start[i]-200000){
                    overlpss<-rbind(overlpss, re2[j,])
                    overlptb<-rbind(overlptb, re3[k,])
                    overlppw<-rbind(overlppw,pws[i,])}
                }
            }
    }}
}      

ov<-overlpss[-3,]
ov$end[2]<-27000000
ov<-ov[,c(1:4,6)]
ov<-rbind(ov,ov,ov)
ov$pop[5:8]<-"PWS"
ov$pop[9:12]<-"TB"
ov$cov23[5:8]<-overlppw[c(1,2,4,5),"cov23"]
ov$cov23[9:12]<-overlptb[c(1,2,4,5),"cov23"]

write.csv(ov[,1:3], "../Output/COV/COVscan/Overlap_regions_COV23_3Pops_plusminus200k.csv", row.names = F)

sink("../Output/COV/COVscan/overlap_cov23_3pop.bed")
cat("track type=bedGraph \n")
options(scipen=999)
for (i in 1:4){
    cat(paste0(ov$chrom[i],"\t",ov$start[i], "\t", ov$end[i], "\n"))
}
sink(NULL)

p23_ano<-read.table("../Output/COV/COVscan/PWS_outliers_cov23_annotation", sep=" ")
p23_ano2<-read.table("../Output/COV/COVscan/SS_outliers_cov23_annotation", sep=" ")
p23_ano3<-read.table("../Output/COV/COVscan/TB_outliers_cov23_annotation", sep=" ")

common<-p23_ano[p23_ano$V1 %in% ov$chrom,]
common2<-p23_ano2[p23_ano2$V1 %in% ov$chrom,]
common3<-p23_ano3[p23_ano3$V1 %in% ov$chrom,]

common<-rbind(common, common2, common3)
common<-common[!duplicated(common),]

genes<-data.frame()
for (i in 1:4){
    df<-common[common$V2>=ov$start[i] & common$V2<=ov$end[i] & common$V1==ov$chrom[i],]
    genes<-rbind(genes,df)
}

# Perse the gene info
annotations<-data.frame()
for (i in 1: nrow(genes)){
    anns<-unlist(strsplit(genes$V4[i], "\\,|\\|"))
    annm<-data.frame(matrix(anns,ncol = 16, byrow = TRUE))
    annm<-annm[,c(2,3,4,5,8)]
    colnames(annm)<-c("Effect","Putative_impact","Gene_name","Gene_ID","Feature type")
    annm<-annm[!duplicated(annm), ]
    annm$chr<-genes$V1[i]
    annm$pos<-genes$V2[i]
    annm$AF<-genes$V3[i]
    annotations<-rbind(annotations, annm)
}     
annotations <-annotations[!duplicated(annotations), ]
annotations<-annotations[,c(6:8,1:5)]

write.csv(annotations, "../Output/COV/COVscan/Genes_PWSonly_outliers_100k_cov12.csv", row.names = F)
annotations<-cbind(df[,1:2], annotations)
colnames(annotations)<-c("chr", "pos", "Annotation","Putative_impact","Gene_name", "Gene_ID", "Transcript_biotype","Annotation2","Putative_impact2","Gene_name2", "Gene_ID2", "Transcript_biotype2")


ano<-annotations[!(duplicated(annotations[,3:6])),]
focus<-ano[ano$pos>=26425000& ano$pos<=26490000,]
write.csv(focus, "../Output/PCA/genes/Chr20_genes_in_26.4-26.6M.csv")
## Check chromosome overlap

2 Compare results from PWSonly and PH-3pops VCF files

pws1<-read.csv("../Output/COV/PWSonly_top1percent_outlier_cov12_overlap.csv")
pws1<-pws1[pws1$window=="100k",]
pws2<-read.csv("../Output/COV/3pops_top1percent_outlier_regions.cov12.csv")
pws2<-pws2[pws2$pop=="PWS"&pws2$window=="100k",]

pws1$vcf<-"PWSonly"
pws2$vcf<-"3Pops"

pws<-rbind(pws1[,c("chrom","start","end","cov12","vcf")],pws2[,c("chrom","start","end","cov12","vcf")])
ggplot(data=pws,aes(x=start, y=cov12, color=vcf, fill=vcf))+
    facet_wrap(~chrom)+
    geom_point()+
    ggtitle("PWS COV12")
ggsave("../Output/COV/COVscan/PWSonly_3Pops_Outlier_overlap_cov12.png", width = 10, height = 8, dpi=300)
    
pws1<-read.csv("../Output/COV/PWSonly_top1percent_outlier_cov23_overlap.csv")
pws1<-pws1[pws1$window=="100k",]
pws2<-read.csv("../Output/COV/3pops_top1percent_outlier_regions.cov23.csv")
pws2<-pws2[pws2$pop=="PWS"&pws2$window=="100k",]

pws1$vcf<-"PWSonly"
pws2$vcf<-"3Pops"

pws<-rbind(pws1[,c("chrom","start","end","cov23","vcf")],pws2[,c("chrom","start","end","cov23","vcf")])
ggplot(data=pws,aes(x=start, y=cov23, color=vcf, fill=vcf))+
    facet_wrap(~chrom)+
    geom_point()+
    ggtitle("PWS COV23")
ggsave("../Output/COV/COVscan/PWSonly_3Pops_Outlier_overlap_cov23.png", width = 10, height = 8, dpi=300)
    
pws1<-read.csv("../Output/COV/PWSonly_top1percent_outlier_cov13_overlap.csv")
pws1<-pws1[pws1$window=="100k",]
pws2<-read.csv("../Output/COV/3pops_top1percent_outlier_regions.cov13.csv")
pws2<-pws2[pws2$pop=="PWS"&pws2$window=="100k",]

pws1$vcf<-"PWSonly"
pws2$vcf<-"3Pops"

pws<-rbind(pws1[,c("chrom","start","end","cov13","vcf")],pws2[,c("chrom","start","end","cov13","vcf")])
ggplot(data=pws,aes(x=start, y=cov13, color=vcf, fill=vcf))+
    facet_wrap(~chrom)+
    geom_point()+
    ggtitle("PWS COV13")
ggsave("../Output/COV/COVscan/PWSonly_3Pops_Outlier_overlap_cov13.png", width = 10, height = 8, dpi=300)

3 Find

LS0tCnRpdGxlOiAiQ09WIHNjYW4gMyBwb3B1bGF0aW9ucyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICAgIHRvYzogdHJ1ZSAKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgICB0aGVtZTogbHVtZW4KICAgICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0Kc291cmNlKCIuLi9Sc2NyaXB0cy9CYXNlU2NyaXB0cy5SIikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShzY2FsZXMpCmBgYAoKIyBGaW5kIHJlZ2lvbnMgd2l0aCBoaWdoIGNvdmFyaWFuY2VzIGluIGVhY2ggcG9wdWxhdGlvbgoqIEZyb20gVGVtcG9yYWwgQ292YXJpYW5jZSBhbmFseXNpcyAgLW91dHB1dCBjb3ZhcmlhbmNlcyBmb3IgZWFjaCB0aW1lIHBlcmlvZAoKIyMgUGxvdCB0aGUgY292YXJpYW5jZXMgYWNyb3NzIHRoZSBnZW5vbWUgIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiNGaW5kIHRoZSByZWdpb25zIHdpdGggYSBoaWdoIHRlbXBvcmFsIGNvdmFyaWFuY2UgCnBvcHM8LWMoIlBXUyIsIlRCIiwiU1MiKQp3aW5zaXplPC1jKCI1MGsiLCIxMDBrIiwiMjUwayIpCmV2ZW5zPC1wYXN0ZTAoImNociIsc2VxKDIsMjYsIGJ5PTIpKQpjb3YubGlzdDwtbGlzdCgpCmNvdnNfYWxsPC1saXN0KCkKaz0xCmZvciAocCBpbiAyOiBsZW5ndGgocG9wcykpewogICAgcG9wPC1wb3BzW3BdCiAgICBmb3IgKGkgaW4gMTogbGVuZ3RoKHdpbnNpemUpKXsKICAgICAgICBpdjwtcmVhZC5jc3YocGFzdGUwKCJ+L1Byb2plY3RzL1BhY2hlcnJpbmdfVmluY2VudC9NRDcwMDAvTUQ3MDAwXzNwb3BzX2ludGVydmFsc18iLHdpbnNpemVbaV0sIndpbmRvdy5jc3YiKSwgcm93Lm5hbWVzID0gMSkKICAgICAgICBpZiAocD09MykgewogICAgICAgICAgICBjb3YyMzwtcmVhZC5jc3YocGFzdGUwKCJ+L1Byb2plY3RzL1BhY2hlcnJpbmdfVmluY2VudC9NRDcwMDAvIixwb3AsIl9jb3YyM18yMDE3LTIwMDZfMjAwNi0xOTk2X21kNzAwMF8iLHdpbnNpemVbaV0sIndpbmRvdy5jc3YiKSwgaGVhZGVyID0gRikKICAgICAgICAgICAgY292czwtY2JpbmQoaXYsIGNvdjIzKQogICAgICAgICAgICBjb2xuYW1lcyhjb3ZzKVs0XTwtYygiY292MjMiKQogICAgICAgICAgICBjb3ZzJGluZGV4PTE6bnJvdyhjb3ZzKQogICAgICAgICAgICBjb3ZzJGNvbG9yPC0iY29sMSIKICAgICAgICAgICAgY292cyRjb2xvcltjb3ZzJGNocm9tICVpbiUgZXZlbnNdPC0iY29sMiIKICAgIAogICAgICAgICAgICBjb3ZzW3NhcHBseShjb3ZzLCBpcy5pbmZpbml0ZSldIDwtIE5BCiAgICAgICAgICAgIGNvdnNbc2FwcGx5KGNvdnMsIGlzLm5hbildIDwtIE5BCiAgICAgICAgICAgIAogICAgICAgICAgICBjb3YubGlzdFtba11dPC1jb3ZzCiAgICAgICAgICAgIG5hbWVzKGNvdi5saXN0KVtrXTwtcGFzdGUwKHBvcCwiXyIsd2luc2l6ZVtpXSkgICAgCiAgICAgICAgICAgIGs9aysxCiAgICAgICAgICAgIAogICAgICAgICAgICB5PC1taW4oY292cyRjb3YyMywgbmEucm09VCkKICAgICAgICAgICAgeW1pbjwtaWZlbHNlICh5PD0tMC4xLC0wLjEsIHkpIAogICAgICAgICAgICB5bWF4PC1tYXgoY292cyRjb3YyMywgbmEucm09VCkKICAgICAgICAgICAgZ2dwbG90KGNvdnMsIGFlcyh4PWluZGV4LCB5PWNvdjIzLCBjb2xvcj1jb2xvcikpKwogICAgICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPTEsIGFscGhhPTAuNSkrCiAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICAgICAgICAgICAgICB5bGltKHltaW4seW1heCkrCiAgICAgICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImdyYXk3MCIsInN0ZWVsYmx1ZSIpLCBndWlkZT0ibm9uZSIpKwogICAgICAgICAgICAgICAgeWxhYigiQ292YXJpYW5jZSIpK3hsYWIoJ0Nocm9tb3NvbWUnKSsKICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgICAgICAgICAgICAgIGdndGl0bGUocGFzdGUwKHBvcCwiICIsIHdpbnNpemVbaV0sIiB3aW5kb3ciKSkKICAgICAgICAgICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L0NPVi8iLHBvcCwiX3RlbXBDb3ZzX2Fjcm9zc0dlbm9tZV8iLHdpbnNpemVbaV0sICJXaW5kb3cucG5nIiksIHdpZHRoID0gOCwgaGVpZ2h0ID0gMi43LCBkcGk9MzAwKSAKICAgICAgICB9CiAgICAgICAgZWxzZSB7CiAgICAgICAgICAgIGNvdjEyPC1yZWFkLmNzdihwYXN0ZTAoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L01ENzAwMC8iLHBvcCwiX2NvdjEyXzE5OTYtMTk5MV8yMDA2LTE5OTZfbWQ3MDAwXyIsd2luc2l6ZVtpXSwid2luZG93LmNzdiIpLCBoZWFkZXIgPSBGKQogICAgICAgICAgICBjb3YyMzwtcmVhZC5jc3YocGFzdGUwKCJ+L1Byb2plY3RzL1BhY2hlcnJpbmdfVmluY2VudC9NRDcwMDAvIixwb3AsIl9jb3YyM18yMDE3LTIwMDZfMjAwNi0xOTk2X21kNzAwMF8iLHdpbnNpemVbaV0sIndpbmRvdy5jc3YiKSwgaGVhZGVyID0gRikKICAgICAgICAgICAgY292MTM8LXJlYWQuY3N2KHBhc3RlMCgifi9Qcm9qZWN0cy9QYWNoZXJyaW5nX1ZpbmNlbnQvTUQ3MDAwLyIscG9wLCJfY292MTNfMjAxNy0yMDA2XzE5OTYtMTk5MV9tZDcwMDBfIix3aW5zaXplW2ldLCJ3aW5kb3cuY3N2IiksIGhlYWRlciA9IEYpCiAgICAgICAgICAgIGNvdnM8LWNiaW5kKGl2LCBjb3YxMiwgY292MjMsY292MTMpCiAgICAgICAgICAgIGNvbG5hbWVzKGNvdnMpWzQ6Nl08LWMoImNvdjEyIiwiY292MjMiLCJjb3YxMyIpCiAgICAgICAgICAgIGNvdnMkaW5kZXg9MTpucm93KGNvdnMpCiAgICAKICAgICAgICAgICAgY292cyRjb2xvcjwtImNvbDEiCiAgICAgICAgICAgIGNvdnMkY29sb3JbY292cyRjaHJvbSAlaW4lIGV2ZW5zXTwtImNvbDIiCiAgICAKICAgICAgICAgICAgY292c1tzYXBwbHkoY292cywgaXMuaW5maW5pdGUpXSA8LSBOQQogICAgICAgICAgICBjb3ZzW3NhcHBseShjb3ZzLCBpcy5uYW4pXSA8LSBOQQogICAgICAgICAgICAKICAgICAgICAgICAgY292Lmxpc3RbW2tdXTwtY292cwogICAgICAgICAgICBuYW1lcyhjb3YubGlzdClba108LXBhc3RlMChwb3AsIl8iLHdpbnNpemVbaV0pICAgIAogICAgICAgICAgICBrPWsrMQogICAgICAgICAgICBjb3ZzbTwtbWVsdChjb3ZzWyxjKCJpbmRleCIsImNvbG9yIiwiY292MTIiLCJjb3YyMyIsImNvdjEzIildLCBpZC52YXJzID0gYygiaW5kZXgiLCAiY29sb3IiKSkKICAgICAgICAgICAgeW1heDwtbWF4KGNvdnNtJHZhbHVlLCBuYS5ybT1UKQogICAgICAgICAgICB5PC1taW4oY292c20kdmFsdWUsIG5hLnJtPVQpCiAgICAgICAgICAgIHltaW48LWlmZWxzZSAoeTw9LTAuMSwtMC4xLCB5KSAKICAgICAgICAgICAgZ2dwbG90KGNvdnNtLCBhZXMoeD1pbmRleCwgeT12YWx1ZSwgY29sb3I9Y29sb3IpKSsKICAgICAgICAgICAgICAgIGZhY2V0X3dyYXAofnZhcmlhYmxlLCBucm93PTMpKwogICAgICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPTEsIGFscGhhPTAuNSkrCiAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICAgICAgICAgICAgICB5bGltKHltaW4seW1heCkrCiAgICAgICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImdyYXk3MCIsInN0ZWVsYmx1ZSIpLCBndWlkZT0ibm9uZSIpKwogICAgICAgICAgICAgICAgeWxhYigiQ292YXJpYW5jZSIpK3hsYWIoJ0Nocm9tb3NvbWUnKSsKICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgICAgICAgICAgICAgIGdndGl0bGUocGFzdGUwKHBvcCwiICIsIHdpbnNpemVbaV0sIiB3aW5kb3ciKSkKICAgICAgICAgICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L0NPVi8iLHBvcCwiX3RlbXBDb3ZzX2Fjcm9zc0dlbm9tZV8iLHdpbnNpemVbaV0sICJXaW5kb3cucG5nIiksIHdpZHRoID0gOCwgaGVpZ2h0ID0gOCwgZHBpPTMwMCkgICAgCiAgICAgICAgfQogICAgfQogICAgCn0KCgpgYGAKCiFbXSguLi9PdXRwdXQvQ09WL1BXU190ZW1wQ292c19hY3Jvc3NHZW5vbWVfMTAwa1dpbmRvdy5wbmcpe3dpZHRoPTY1JX0KCgohW10oLi4vT3V0cHV0L0NPVi9UQl90ZW1wQ292c19hY3Jvc3NHZW5vbWVfMTAwa1dpbmRvdy5wbmcpe3dpZHRoPTY1JX0gICAKCiFbXSguLi9PdXRwdXQvQ09WL1NTX3RlbXBDb3ZzX2Fjcm9zc0dlbm9tZV8xMDBrV2luZG93LnBuZyl7d2lkdGg9NjUlfSAgIAoKIVtdKC4uL091dHB1dC9DT1YvUFdTX3RlbXBDb3ZzX2Fjcm9zc0dlbm9tZV8yNTBrV2luZG93LnBuZyl7d2lkdGg9NjUlfSAKCiFbXSguLi9PdXRwdXQvQ09WL1RCX3RlbXBDb3ZzX2Fjcm9zc0dlbm9tZV8yNTBrV2luZG93LnBuZyl7d2lkdGg9NjUlfSAKCiFbXSguLi9PdXRwdXQvQ09WL1NTX3RlbXBDb3ZzX2Fjcm9zc0dlbm9tZV8yNTBrV2luZG93LnBuZyl7d2lkdGg9NjUlfSAKCgoKIyMgRmluZCB0aGUgb3V0bGllciByZWdpb25zIGZvciBlYWNoIHRpbWUgcGVyaW9kICAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojZmluZCBob3cgb3V0bGllcnMgb3ZlcmxhcCBiZXR3ZWVuIGRpZmZlcmVudCB3aW5kb3dzCmNvdjEyPC1kYXRhLmZyYW1lKCkKY292MjM8LWRhdGEuZnJhbWUoKQpjb3YxMzwtZGF0YS5mcmFtZSgpCgpmb3IgKGkgaW4gMTpsZW5ndGgoY292Lmxpc3QpKXsKIGlmIChncmVwbCgiUFdTIixuYW1lcyhjb3YubGlzdClbaV0pfGdyZXBsKCJUQiIsbmFtZXMoY292Lmxpc3QpW2ldKSl7CiAgICBjb3ZzPC1jb3YubGlzdFtbaV1dCiAgICAKICAgIHBvcDwtZ3N1YigiXy4rIiwnJywgbmFtZXMoY292Lmxpc3QpW2ldKQogICAgd2luPC1nc3ViKHBhc3RlMChwb3AsIl8iKSwgJycsIG5hbWVzKGNvdi5saXN0KVtpXSkKICAgIAogICAgY292czwtY292c1tvcmRlcihjb3ZzJGNvdjEyLCBkZWNyZWFzaW5nPVQpLF0KICAgIG48LWNlaWxpbmcobnJvdyhjb3ZzKSowLjAxKSAjdG9wMSUgcmVnaW9uCiAgICBjb3ZzMTJfdG9wPC1jb3ZzWzE6bixjKDE6NCldCiAgICBjb3ZzMTJfdG9wPC1jb3ZzMTJfdG9wW29yZGVyKGNvdnMxMl90b3AkY2hyb20sIGNvdnMxMl90b3Akc3RhcnQpLF0KICAgIGNvdnMxMl90b3Akd2luZG93PC13aW4KICAgIGNvdnMxMl90b3AkcG9wPC1wb3AKICAgIGNvdjEyPC1yYmluZChjb3YxMiwgY292czEyX3RvcCkKICAgIAogICAgY292czwtY292c1tvcmRlcihjb3ZzJGNvdjEzLCBkZWNyZWFzaW5nPVQpLF0KICAgIG48LWNlaWxpbmcobnJvdyhjb3ZzKSowLjAxKSAjdG9wMSUgcmVnaW9uCiAgICBjb3ZzMTNfdG9wPC1jb3ZzWzE6bixjKDE6Myw2KV0KICAgIGNvdnMxM190b3A8LWNvdnMxM190b3Bbb3JkZXIoY292czEzX3RvcCRjaHJvbSwgY292czEzX3RvcCRzdGFydCksXQogICAgY292czEzX3RvcCR3aW5kb3c8LXdpbgogICAgY292czEzX3RvcCRwb3A8LXBvcAogICAgY292MTM8LXJiaW5kKGNvdjEzLCBjb3ZzMTNfdG9wKQogICAgCiAgICBjb3ZzPC1jb3ZzW29yZGVyKGNvdnMkY292MjMsIGRlY3JlYXNpbmc9VCksXQogICAgbjwtY2VpbGluZyhucm93KGNvdnMpKjAuMDEpICN0b3AxJSByZWdpb24KICAgIGNvdnMyM190b3A8LWNvdnNbMTpuLGMoMTozLDUpXQogICAgY292czIzX3RvcDwtY292czIzX3RvcFtvcmRlcihjb3ZzMjNfdG9wJGNocm9tLCBjb3ZzMjNfdG9wJHN0YXJ0KSxdCiAgICBjb3ZzMjNfdG9wJHdpbmRvdzwtd2luCiAgICBjb3ZzMjNfdG9wJHBvcDwtcG9wCiAgICBjb3YyMzwtcmJpbmQoY292MjMsIGNvdnMyM190b3ApCiB9CiBpZiAoZ3JlcGwoIlNTIixuYW1lcyhjb3YubGlzdClbaV0pKXsKICAgIGNvdnM8LWNvdi5saXN0W1tpXV0KICAgIAogICAgcG9wPC1nc3ViKCJfLisiLCcnLCBuYW1lcyhjb3YubGlzdClbaV0pCiAgICB3aW48LWdzdWIocGFzdGUwKHBvcCwiXyIpLCAnJywgbmFtZXMoY292Lmxpc3QpW2ldKQogICAgCiAgICBjb3ZzPC1jb3ZzW29yZGVyKGNvdnMkY292MjMsIGRlY3JlYXNpbmc9VCksXQogICAgbjwtY2VpbGluZyhucm93KGNvdnMpKjAuMDEpICN0b3AxJSByZWdpb24KICAgIGNvdnMyM190b3A8LWNvdnNbMTpuLGMoMTo0KV0KICAgIGNvdnMyM190b3A8LWNvdnMyM190b3Bbb3JkZXIoY292czIzX3RvcCRjaHJvbSwgY292czIzX3RvcCRzdGFydCksXQogICAgY292czIzX3RvcCR3aW5kb3c8LXdpbgogICAgY292czIzX3RvcCRwb3A8LXBvcAogICAgY292MjM8LXJiaW5kKGNvdjIzLCBjb3ZzMjNfdG9wKQogICAgCiAgICB9Cn0KCgp3cml0ZS5jc3YoY292MTIsICIuLi9PdXRwdXQvQ09WLzNwb3BzX3RvcDFwZXJjZW50X291dGxpZXJfcmVnaW9ucy5jb3YxMi5jc3YiLHJvdy5uYW1lcyA9IEYpCndyaXRlLmNzdihjb3YyMywgIi4uL091dHB1dC9DT1YvM3BvcHNfdG9wMXBlcmNlbnRfb3V0bGllcl9yZWdpb25zLmNvdjIzLmNzdiIscm93Lm5hbWVzID0gRikKd3JpdGUuY3N2KGNvdjEzLCAiLi4vT3V0cHV0L0NPVi8zcG9wc190b3AxcGVyY2VudF9vdXRsaWVyX3JlZ2lvbnMuY292MTMuY3N2Iixyb3cubmFtZXMgPSBGKQoKYGBgCgoKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNDcmVhdGUgcGxvdHMgd2l0aCBkaWZmZXJlbnQgY29sb3JzIGZvciBvdXRsaWVycwojZm9yIENPVjEyIGFuZCBDT1YxMyBmb3IgVEIgYW5kIFBXUyAoMTAwSykKY3Y8LWMoImNvdjEyIiwiY292MTMiLCJjb3YyMyIpCndpbnNpemU8LWMoIjUwayIsIjEwMGsiLCIyNTBrIikKCmZvciAoaSBpbiAxOmxlbmd0aChjdikpewogICAgaWYgKGk9PTF8aT09Mil7CiAgICAgICAgZm9yICh3IGluIDE6IGxlbmd0aCh3aW5zaXplKSl7CiAgICAgICAgICAgICNQV1MKICAgICAgICAgICAgZGYxPC1jb3YubGlzdFtbcGFzdGUwKCJQV1NfIiwgd2luc2l6ZVt3XSldXQogICAgICAgICAgICBkZjE8LWRmMVtvcmRlcihkZjFbLGN2W2ldXSwgZGVjcmVhc2luZz1UKSxdCiAgICAgICAgICAgIG48LWNlaWxpbmcobnJvdyhkZjEpKjAuMDEpICN0b3AxJSByZWdpb24KICAgICAgICAgICAgZGYxJHRvcDE8LSJOIgogICAgICAgICAgICBkZjEkdG9wMVsxOm5dPC0iUFdTIgogICAgICAgICAgICAKICAgICAgICAgICAgI3RiCiAgICAgICAgICAgIGRmMjwtY292Lmxpc3RbW3Bhc3RlMCgiVEJfIiwgd2luc2l6ZVt3XSldXQogICAgICAgICAgICBkZjI8LWRmMltvcmRlcihkZjJbLGN2W2ldXSwgZGVjcmVhc2luZz1UKSxdCiAgICAgICAgICAgIGRmMiR0b3AxPC0iTiIKICAgICAgICAgICAgZGYyJHRvcDFbMTpuXTwtIlRCIgogICAgICAgICAgICAKICAgICAgICAgICAgY288LXJiaW5kKGRmMSwgZGYyKQogICAgCiAgICAgICAgICAgIGNvJGNocm9tPC1mYWN0b3IoY28kY2hyb20sIGxldmVscz1wYXN0ZTAoImNociIsIDE6MjYpKQogICAgICAgICAgICBjbyR0b3AxPC1mYWN0b3IoY28kdG9wMSwgbGV2ZWxzPWMoIlBXUyIsIlRCIiwiTiIpKQogICAgICAgICAgICBjb2xuYW1lcyhjbylbd2hpY2goY29sbmFtZXMoY28pPT1jdltpXSldPC0iY292IgogICAgCiAgICAgICAgICAgIHltYXg8LW1heChjbyRjb3YsIG5hLnJtPVQpCiAgICAgICAgICAgIGdncGxvdChjbywgYWVzKHg9c3RhcnQvMTAwMDAwMCwgeT1jb3YsIGNvbG9yPXRvcDEpKSsKICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZT0wLjUpKwogICAgICAgICAgICAgICAgZmFjZXRfd3JhcCh+Y2hyb20sIG5jb2w9NCkrCiAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkreWxpbSgtMC4xLHltYXgpKwogICAgICAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJkZWVwcGluayIsIm9yYW5nZSIgLCIjQUREOEU2ODAiKSwgbGFiZWxzPWMoIlBXUyIsICJUQiIsICIiKSkrCiAgICAgICAgICAgICAgICB5bGFiKCJDb3ZhcmlhbmNlIikreGxhYignUG9zdGlvbiAoTWIpJykrCiAgICAgICAgICAgICAgICBnZ3RpdGxlKHBhc3RlMCh3aW5zaXplW3ddLCIgd2luZG93ICIsY3ZbaV0pKSsKICAgICAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkrCiAgICAgICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChjb2xvcj1jKCJkZWVwcGluayIsIm9yYW5nZSIsIndoaXRlIikpLCB0aXRsZT1lbGVtZW50X3RleHQoIlRvcCAxJSIpKSkKICAgCiAgICAgICAgICAgICAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vIixjdltpXSwiX3BlckNocm9tXyIsd2luc2l6ZVt3XSwgIldpbmRvd19PdXRsaWVycy5wbmciKSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCwgZHBpPTMwMCkKICAgICAgICB9CiAgICAgICAKICAgIH0KICAgCiAgICBpZiAoaT09Myl7CiAgICAgICAgZm9yICh3IGluIDE6IGxlbmd0aCh3aW5zaXplKSl7CiAgICAgICAgI3B3cwogICAgICAgIGRmMTwtY292Lmxpc3RbW3Bhc3RlMCgiUFdTXyIsIHdpbnNpemVbd10pXV0KICAgICAgICBkZjE8LWRmMVssYygiY2hyb20iLCJzdGFydCIsImVuZCIsImNvdjIzIildCiAgICAgICAgZGYxPC1kZjFbb3JkZXIoZGYxJGNvdjIzLCBkZWNyZWFzaW5nPVQpLF0KICAgICAgICBuPC1jZWlsaW5nKG5yb3coZGYxKSowLjAxKSAjdG9wMSUgcmVnaW9uCiAgICAgICAgZGYxJHRvcDE8LSJOIgogICAgICAgIGRmMSR0b3AxWzE6bl08LSJQV1MiCiAgICAKICAgICAgICAjdGIKICAgICAgICBkZjI8LWNvdi5saXN0W1twYXN0ZTAoIlRCXyIsIHdpbnNpemVbd10pXV0KICAgICAgICBkZjI8LWRmMlssYygiY2hyb20iLCJzdGFydCIsImVuZCIsImNvdjIzIildCiAgICAgICAgZGYyPC1kZjJbb3JkZXIoZGYyJGNvdjIzLCBkZWNyZWFzaW5nPVQpLF0KICAgICAgICBkZjIkdG9wMTwtIk4iCiAgICAgICAgZGYyJHRvcDFbMTpuXTwtIlRCIgogICAgCiAgICAgICAgI3NzCiAgICAgICAgZGYzPC1jb3YubGlzdFtbcGFzdGUwKCJTU18iLCB3aW5zaXplW3ddKV1dCiAgICAgICAgZGYzPC1kZjNbLGMoImNocm9tIiwic3RhcnQiLCJlbmQiLCJjb3YyMyIpXQogICAgICAgIGRmMzwtZGYzW29yZGVyKGRmMyRjb3YyMywgZGVjcmVhc2luZz1UKSxdCiAgICAgICAgZGYzJHRvcDE8LSJOIgogICAgICAgIGRmMyR0b3AxWzE6bl08LSJTUyIKCiAgICAgICAgY288LXJiaW5kKGRmMSxkZjIsZGYzKQoKICAgICAgICBjbyRjaHJvbTwtZmFjdG9yKGNvJGNocm9tLCBsZXZlbHM9cGFzdGUwKCJjaHIiLCAxOjI2KSkKICAgICAgICBjbyR0b3AxPC1mYWN0b3IoY28kdG9wMSwgbGV2ZWxzPWMoIlBXUyIsIlRCIiwiU1MiLCJOIikpCiAgICAgICAgeW1heDwtbWF4KGNvJGNvdjIzLCBuYS5ybT1UKQogICAgICAgIGdncGxvdChjbywgYWVzKHg9c3RhcnQvMTAwMDAwMCwgeT1jb3YyMywgY29sb3I9dG9wMSkpKwogICAgICAgICAgICBnZW9tX3BvaW50KHNpemU9MC41KSsKICAgICAgICAgICAgZmFjZXRfd3JhcCh+Y2hyb20sIG5jb2w9NCkrCiAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSt5bGltKC0wLjEseW1heCkrCiAgICAgICAgICAgIHlsYWIoIkNvdmFyaWFuY2UiKSt4bGFiKCdQb3N0aW9uIChNYiknKSsKICAgICAgICAgICAgZ2d0aXRsZShwYXN0ZTAod2luc2l6ZVt3XSwiIHdpbmRvdyAiLGN2W2ldKSkrCiAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkrCiAgICAgICAgICAgICNzY2FsZV9jb2xvcl9kaXNjcmV0ZShicmVha3M9YygiUFdTIiwiU1MiLCJUQiIpKSsKICAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJkZWVwcGluayIsIm9yYW5nZSIsZ3JlLCIjQUREOEU2NjYiKSwgbGFiZWxzPWMoIlBXUyIsIlRCIiwiU1MiLCAiIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChjb2xvcj1jKCJkZWVwcGluayIsIm9yYW5nZSIsZ3JlLCAgICAgICAgICJ3aGl0ZSIpKSx0aXRsZT1lbGVtZW50X3RleHQoIlRvcCAxJSBvdXRsaWVycyIpKSkgCiAgICAgICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL0NPVjIzXzNQb3BzX3BlckNocm9tXyIsd2luc2l6ZVt3XSwgIldpbmRvd19PdXRsaWVycy5wbmciKSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOSwgZHBpPTMwMCkKICAgICAgICB9CiAgICB9CiAgICAKfQoKCmBgYAoKCgoKCgohW10oLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL2NvdjEyX3BlckNocm9tXzEwMGtXaW5kb3dfT3V0bGllcnMucG5nKQoKIVtdKC4uL091dHB1dC9DT1YvQ09Wc2Nhbi9jb3YxM19wZXJDaHJvbV8xMDBrV2luZG93X091dGxpZXJzLnBuZykKCiFbXSguLi9PdXRwdXQvQ09WL0NPVnNjYW4vY292MTJfcGVyQ2hyb21fMjUwa1dpbmRvd19PdXRsaWVycy5wbmcpIAohW10oLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL2NvdjEzX3BlckNocm9tXzI1MGtXaW5kb3dfT3V0bGllcnMucG5nKSAKCgohW10oLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL0NPVjIzXzNQb3BzX3BlckNocm9tXzEwMGtXaW5kb3dfT3V0bGllcnMucG5nKSAgCiFbXSguLi9PdXRwdXQvQ09WL0NPVnNjYW4vQ09WMjNfM1BvcHNfcGVyQ2hyb21fMjUwa1dpbmRvd19PdXRsaWVycy5wbmcpICAKCgoKCiMjIFJ1biB0aGUgc25wRWZmIHBpcGVsaW5lIHRvIGZpbmQgYW5ub3RhdGlvbiBpbiB0aGUgb3V0bGllciByZWdpb25zICAKKiBDcmVhdGUgYSBzY3JpcHQgdG8gcnVuIFNucEVmZiAKCkNyZWF0ZSBWQ0YgZmlsZXMgd2l0aCBzZWxlY3RlZCByZWdpb25zICYgcnVuIHNucEVmZiAgCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI0NyZWF0ZSBiZWQgZmlsZXMKY3Y8LWMoImNvdjEyIiwiY292MTMiLCJjb3YyMyIpCgpmb3IgKGkgaW4gMTozKXsKICAgIGRmPC1yZWFkLmNzdihwYXN0ZTAoIi4uL091dHB1dC9DT1YvM3BvcHNfdG9wMXBlcmNlbnRfb3V0bGllcl9yZWdpb25zLiIsY3ZbaV0sIi5jc3YiKSkKICAgIGRmcDwtZGZbZGYkcG9wPT0iUFdTIixdCiAgICB3cml0ZS50YWJsZShkZnBbLDE6M10sIHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL1BXU19vdXRsaWVyc18iLGN2W2ldLCIuYmVkIikscXVvdGUgPSBGLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHNlcCA9ICJcdCIpCiAgICBkZnQ8LWRmW2RmJHBvcD09IlRCIixdCiAgICB3cml0ZS50YWJsZShkZnRbLDE6M10sIHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL1RCX291dGxpZXJzXyIsY3ZbaV0sIi5iZWQiKSxxdW90ZSA9IEYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYsc2VwID0gIlx0IikKICAgIAogICAgaWYgKGk9PTMpewogICAgICAgIGRmczwtZGZbZGYkcG9wPT0iU1MiLF0KICAgICAgICB3cml0ZS50YWJsZShkZnNbLDE6M10sIHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL1NTX291dGxpZXJzXyIsY3ZbaV0sIi5iZWQiKSxxdW90ZSA9IEYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYsc2VwID0gIlx0IikKICAgICAgICAKICAgIH0KfQoKCiNjcmVhdGUgYSBiYXNoIHNjcmlwdCB0byBydW4gc25wRWZmCmJlZGZpbGVzPC1saXN0LmZpbGVzKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vIiwgcGF0dGVybj0iKi5iZWQiKQoKc2luaygiLi4vQ09Wc2Nhbl9jcmVhdGVWQ0ZzLnNoIikKY2F0KCIjIS9iaW4vYmFzaCBcblxuIikKZm9yIChpIGluIDE6bGVuZ3RoKGJlZGZpbGVzKSl7CiAgICBmbmFtZTwtZ3N1YigiLmJlZCIsJycsIGJlZGZpbGVzW2ldKQogICAgY2F0KHBhc3RlMCgidmNmdG9vbHMgLS1nenZjZiBEYXRhL25ld192Y2YvUEhfRFA2MDBfNzAwMF9taW5RMjBfbWluTVEzMF9OUzAuNV9tYWYwNS52Y2YuZ3ogLS1iZWQgT3V0cHV0L0NPVi9DT1ZzY2FuLyIsIGJlZGZpbGVzW2ldLCAiIC0tb3V0IE91dHB1dC9DT1YvQ09Wc2Nhbi8iLCBmbmFtZSwiIC0tcmVjb2RlIC0ta2VlcC1JTkZPLWFsbCBcbiIpKQp9CnNpbmsoTlVMTCkgIAoKI2NyZWF0ZSBhIGJhc2ggc2NyaXB0IHRvIHJ1biBzbnBFZmYKdmZpbGVzPC1saXN0LmZpbGVzKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vIiwgcGF0dGVybj0iLnJlY29kZS52Y2YiKQoKc2luaygifi9wcm9ncmFtcy9zbnBFZmYvcnVuc25wRWZmX2Nvdi5zaCIpCmNhdCgiIyEvYmluL2Jhc2ggXG5cbiIpCmZvciAoaSBpbiAxOmxlbmd0aCh2ZmlsZXMpKXsKICAgIGZuYW1lPC1nc3ViKCIucmVjb2RlLnZjZiIsIiIsdmZpbGVzW2ldKQogICAgY2F0KHBhc3RlMCgiamF2YSAtWG14OGcgLWphciBzbnBFZmYuamFyIENoX3YyLjAuMi45OSB+L1Byb2plY3RzL1BhY0hlcnJpbmcvT3V0cHV0L0NPVi9DT1ZzY2FuLyIsdmZpbGVzW2ldLCAiIC1zdGF0cyB+L1Byb2plY3RzL1BhY0hlcnJpbmcvT3V0cHV0L0NPVi9DT1ZzY2FuLyIsZm5hbWUsIi5odG1sID4gIH4vUHJvamVjdHMvUGFjSGVycmluZy9PdXRwdXQvQ09WL0NPVnNjYW4vQW5uby4iLGZuYW1lLCIudmNmIFxuIikpCiAgICAKICAgICNleHRyYWN0IHRoZSBhbm5vdGF0aW9uIGluZm9ybWF0aW9uCiAgICBjYXQocGFzdGUwKCJiY2Z0b29scyBxdWVyeSAtZiAnJUNIUk9NICVQT1MgJUlORk8vQUYgJUlORk8vQU5OXFxuJyB+L1Byb2plY3RzL1BhY0hlcnJpbmcvT3V0cHV0L0NPVi9DT1ZzY2FuL0Fubm8uIixmbmFtZSwiLnZjZiA+IH4vUHJvamVjdHMvUGFjSGVycmluZy9PdXRwdXQvQ09WL0NPVnNjYW4vIixmbmFtZSwiX2Fubm90YXRpb24gXG5cbiIpKQoKfQpzaW5rKE5VTEwpICAKCmBgYAoKYGBge2Jhc2ggZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KY2Qgfi9Qcm9qZWN0cy9QYWNIZXJyaW5nCmJhc2ggQ09Wc2Nhbl9jcmVhdGVWQ0ZzLnNoCgpjZCB+L3Byb2dyYW1zL3NucEVmZgpiYXNoIHJ1bnNucEVmZl9jb3Yvc2gKYGBgCgoKIyMjIENyZWF0ZSBzdW1tYXJ5IGdlbmUgZmlsZXMgZnJvbSBzbnBFZmYgYW5kIGNoZWNrIG92ZXJsYXBwaW5nIGdlbmVzLgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgQ3JlYXRlIHN1bW1hcnkgZmlsZXMgb2Ygc25wRWZmIHJlc3VsdHMgKGdlbmUgYW5ub3RhdGlvbnMgaW4gdGhlIHJlZ2lvbnMgb2YgaW50ZXJlc3QpIGFuZCByZWZvcm1hdCBhcyBhIFNoaW55R28gaW5wdXQgCgojY3JlYXRlIGdlbmUgbGlzdCAKZ2ZpbGVzPC1saXN0LmZpbGVzKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vIiwgcGF0dGVybj0iZ2VuZXMudHh0IikKCmZvciAoaSBpbiAxOmxlbmd0aChnZmlsZXMpKXsKICAgIGRmPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuLyIsZ2ZpbGVzW2ldKSwgc2VwPSJcdCIpCiAgICBkZjwtZGZbLDE6N10KICAgIGNvbG5hbWVzKGRmKTwtYygiR2VuZU5hbWUiLCJHZW5lSWQiLCJUcmFuc2NyaXB0SWQiLCJCaW9UeXBlIiwidmFyaWFudHNfaW1wYWN0X0hJR0giLCJ2YXJpYW50c19pbXBhY3RfTE9XIiwJInZhcmlhbnRzX2ltcGFjdF9NT0RFUkFURSIpCiAgICAKICAgIGZuYW1lPC1nc3ViKCIuZ2VuZXMudHh0IiwiIixnZmlsZXNbaV0pCiAgICBnZW5lczwtdW5pcXVlKGRmJEdlbmVJZCkKICAgIHNpbmsocGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vZ2VuZUlEbGlzdF8iLGZuYW1lLCIudHh0IikpCiAgICBjYXQocGFzdGUwKGdlbmVzLCI7ICIpKQogICAgc2luayhOVUxMKQp9CgojIEZpbmQgdGhlIGludGVyc2VjdGluZyBnZW5lIG5hbWVzIGFjcm9zcyBwb3B1bGF0aW9ucwoKZ2ZpbGVzMjwtbGlzdC5maWxlcygiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuLyIsIHBhdHRlcm49ImdlbmVJRGxpc3QiKQpnbGlzdDwtbGlzdCgpCmZvciAoaSBpbiAxOmxlbmd0aChnZmlsZXMpKXsKICAgIGRmPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuLyIsZ2ZpbGVzMltpXSksIHNlcD0iOyIpCiAgICBkZjwtdChkZikKICAgIGRmPC1nc3ViKCIgIiwiIixkZikKICAgIGRmMjwtZGZbIWlzLm5hKGRmKV0KICAgIHZuYW1lPC1nc3ViKCIudHh0IiwiIixnZmlsZXMyW2ldLCkKICAgIHZuYW1lPC1nc3ViKCJnZW5lSURsaXN0XyIsIiIsIHZuYW1lKQogICAgZ2xpc3RbW2ldXTwtZGYyCiAgICBuYW1lcyhnbGlzdClbaV08LXZuYW1lCn0KCnRpbWVzPC1jKCJjb3YxMiIsImNvdjEzIiwiY292MjMiKQpjb21tb248LWxpc3QoKQpjb21tb25fZ2VuZXM8LWRhdGEuZnJhbWUodGltZT10aW1lcykKZm9yIChpIGluIDE6Mil7CiAgICB0bGlzdDwtZ2xpc3RbZ3JlcCh0aW1lc1tpXSwgbmFtZXMoZ2xpc3QpKV0KICAgIGlmIChpICE9Myl7CiAgICAgICAgY29tbW9uW1tpXV08LWludGVyc2VjdCh0bGlzdFtbMV1dLCB0bGlzdFtbMl1dKQogICAgICAgIG5hbWVzKGNvbW1vbilbW2ldXTwtdGltZXNbaV0KICAgICAgICBjb21tb25fZ2VuZXMkUFdTW2ldPC1sZW5ndGgodGxpc3RbW2dyZXAoIlBXUyIsIG5hbWVzKHRsaXN0KSldXSkKICAgICAgICBjb21tb25fZ2VuZXMkVEJbaV08LWxlbmd0aCh0bGlzdFtbZ3JlcCgiVEIiLCBuYW1lcyh0bGlzdCkpXV0pCiAgICAgICAgY29tbW9uX2dlbmVzJFNTW2ldPC1OQQogICAgICAgIGNvbW1vbl9nZW5lcyRjb21tb25fUFdTLlRCW2ldPC1sZW5ndGgoaW50ZXJzZWN0KHRsaXN0W1sxXV0sIHRsaXN0W1syXV0pKQogICAgfQogICAgaWYgKGk9PTMpewogICAgICAgIGNvbW1vbl9nZW5lcyRQV1NbaV08LWxlbmd0aCh0bGlzdFtbZ3JlcCgiUFdTIiwgbmFtZXModGxpc3QpKV1dKQogICAgICAgIGNvbW1vbl9nZW5lcyRUQltpXTwtbGVuZ3RoKHRsaXN0W1tncmVwKCJUQiIsIG5hbWVzKHRsaXN0KSldXSkKICAgICAgICBjb21tb25fZ2VuZXMkU1NbaV08LWxlbmd0aCh0bGlzdFtbZ3JlcCgiU1MiLCBuYW1lcyh0bGlzdCkpXV0pCiAgICAgICAgY29tbW9uX2dlbmVzJGNvbW1vbl9QV1MuVEJbaV08LWxlbmd0aChpbnRlcnNlY3QodGxpc3RbWzFdXSwgdGxpc3RbWzNdXSkpCiAgICAgICAgY29tbW9uX2dlbmVzJGNvbW1vbl9QV1MuU1NbaV08LWxlbmd0aChpbnRlcnNlY3QodGxpc3RbWzFdXSwgdGxpc3RbWzJdXSkpCiAgICAgICAgY29tbW9uX2dlbmVzJGNvbW1vbl9TUy5UQltpXTwtbGVuZ3RoKGludGVyc2VjdCh0bGlzdFtbMl1dLCB0bGlzdFtbM11dKSkKICAgICAgICBjb21tb25fZ2VuZXMkY29tbW9uM1tpXTwtbGVuZ3RoKGludGVyc2VjdCh0bGlzdFtbMV1dLGludGVyc2VjdCh0bGlzdFtbMl1dLCB0bGlzdFtbM11dKSkpCiAgICAgICAgaz1pCiAgICAgICAgY29tbW9uW1trXV08LWludGVyc2VjdCh0bGlzdFtbMV1dLCB0bGlzdFtbMl1dKQogICAgICAgIG5hbWVzKGNvbW1vbilbW2tdXTwtcGFzdGUwKHRpbWVzW2ldLCJfUFdTLlNTIikKICAgICAgICBrPWsrMQogICAgICAgIGNvbW1vbltba11dPC1pbnRlcnNlY3QodGxpc3RbWzFdXSwgdGxpc3RbWzNdXSkKICAgICAgICBuYW1lcyhjb21tb24pW1trXV08LXBhc3RlMCh0aW1lc1tpXSwiX1BXUy5UQiIpCiAgICAgICAgaz1rKzEKICAgICAgICBjb21tb25bW2tdXTwtaW50ZXJzZWN0KHRsaXN0W1syXV0sIHRsaXN0W1szXV0pCiAgICAgICAgbmFtZXMoY29tbW9uKVtba11dPC1wYXN0ZTAodGltZXNbaV0sIl9TUy5UQiIpCiAgICAgICAgaz1rKzEKICAgICAgICBjb21tb25bW2tdXTwtaW50ZXJzZWN0KHRsaXN0W1sxXV0saW50ZXJzZWN0KHRsaXN0W1syXV0sIHRsaXN0W1szXV0pKQogICAgICAgIG5hbWVzKGNvbW1vbilbW2tdXTwtcGFzdGUwKHRpbWVzW2ldLCJfM3BvcHMiKQogICAgICAgIH0KICAgIH0KfQogICAgCndyaXRlLmNzdihjb21tb25fZ2VuZXMsICIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vQ29tbW9uX2dlbmVzXzNwb3BzLmNzdiIpCgojV2hhdCBhcmUgdGhlIG92ZXJsYXBwaW5nIGdlbmUgbmFtZXMKCiNhZ2dyZWdhdGUgYWxsIGdlbmUgbmFtZXMKR2VuZXM8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgoZ2ZpbGVzKSl7CiAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbi8iLGdmaWxlc1tpXSksIHNlcD0iXHQiKQogICAgZGY8LWRmWywxOjJdCiAgICBjb2xuYW1lcyhkZik8LWMoIkdlbmVOYW1lIiwiR2VuZUlkIikKICAgIGRmPC1kZlshZHVwbGljYXRlZChkZiksXQogICAgR2VuZXM8LXJiaW5kKEdlbmVzLCBkZikKICAgIEdlbmVzPC1HZW5lc1shZHVwbGljYXRlZChHZW5lcyksXQp9Cgpmb3IgKGkgaW4gMTogbGVuZ3RoKGNvbW1vbikpewogICAgZ2lkczwtY29tbW9uW1tpXV0KICAgIGRmPC1kYXRhLmZyYW1lKEdlbmVJZD1naWRzKQogICAgCiAgICBkZjwtbWVyZ2UoZGYsIEdlbmVzLCBieT0iR2VuZUlkIikKICAgIHdyaXRlLmNzdihkZiwgcGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vQ29tbW9uX2dlbmVzXyIsIG5hbWVzKGNvbW1vbilbaV0sIi5jc3YiKSwgcm93Lm5hbWVzID0gRikKICAgIAp9CgpgYGAKCiMjIyMgT3ZlcmxhcHBpbmcgZ2VuZSBudW1iZXJzICAgCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIFN1bW1hcnkgdGFibGUKY29tbW9uX2dlbmVzPC1yZWFkLmNzdigiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL0NvbW1vbl9nZW5lc18zcG9wcy5jc3YiLCByb3cubmFtZXMgPSAxKQprbml0cjo6a2FibGUoY29tbW9uX2dlbmVzKQoKYGBgCgojIyMjIE92ZXJsYXBwaW5nIHJlZ2lvbnMKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBGaW5kIHRoZSBvdmVybGFwcGluZyByZWdpb25zIHdoZXJlIHRoZSA0IGdlbmVzIGJlbG9uZyB0bzoKY292MjNfYWxsPC1yZWFkLmNzdigiLi4vT3V0cHV0L0NPVi8zcG9wc190b3AxcGVyY2VudF9vdXRsaWVyX3JlZ2lvbnMuY292MjMuY3N2IikKY292MjNfYWxsPC1jb3YyM19hbGxbY292MjNfYWxsJHdpbmRvdz09IjEwMGsiLF0KcHdzPC1jb3YyM19hbGxbY292MjNfYWxsJHBvcD09IlBXUyIsXQp0YjwtY292MjNfYWxsW2NvdjIzX2FsbCRwb3A9PSJUQiIsXQpzczwtY292MjNfYWxsW2NvdjIzX2FsbCRwb3A9PSJTUyIsXQoKI092ZXJsYXAgYmV0d2VlbiBQV1MgYW5kIFRCCnB3cyRpZDwtcGFzdGUwKHB3cyRjaHJvbSwiXyIscHdzJHN0YXJ0KQp0YiRpZDwtcGFzdGUwKHRiJGNocm9tLCJfIix0YiRzdGFydCkKc3MkaWQ8LXBhc3RlMChzcyRjaHJvbSwiXyIsc3Mkc3RhcnQpCmludGVyc2VjdChwd3MkaWQsIHRiJGlkKSAKI1sxXSAiY2hyMTNfMjkyMDAwMDAiICJjaHIxNl82NDAwMDAwIiAgImNocjE2XzI2ODAwMDAwIiAiY2hyMThfMjgwMDAwMCIgICJjaHIxOF8xMjcwMDAwMCIgImNocjIwXzc1MDAwMDAiIAojWzddICJjaHI1XzEzNDAwMDAwIiAgImNocjlfMjU2MDAwMDAiIAojOCByZWdpb25zIGV4YWN0bHkgbWF0Y2gKCmludGVyc2VjdChwd3MkaWQsIHNzJGlkKSAKIyAiY2hyMTBfMTA5MDAwMDAiICJjaHIxMl8yODUwMDAwMCIgImNocjE4XzI4MDAwMDAiICAiY2hyMjVfMTEwMDAwMCIgICJjaHIzXzIwMjAwMDAwIiAgImNocjRfMzEwMDAwMDAiIAoKaW50ZXJzZWN0KHRiJGlkLCBzcyRpZCkgCiMiY2hyMTNfMjI4MDAwMDAiICJjaHIxNF8zMzAwMDAwIiAgImNocjE3Xzk3MDAwMDAiICAiY2hyMThfMjgwMDAwMCIgICJjaHIyXzkwMDAwMCIgICAKCmludGVyc2VjdChwd3MkaWQsIGludGVyc2VjdChzcyRpZCwgdGIkaWQpKQojY2hyMThfMjgwMDAwMCIKCgojIyMjIENoZWNrIGNocm9tb3NvbWUgcmVnaW9uIG92ZXJsYXAgKy0xMDAsMDAwIGJhc2VzCgpvdmVybHBzPC1kYXRhLmZyYW1lKCkKb3ZlcmxwczI8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhwd3MpKXsKICAgIHJlMjwtdGJbdGIkY2hyb209PXB3cyRjaHJvbVtpXSxdCiAgICBpZiAobnJvdyhyZTIpPj0xKXsKICAgICAgICBmb3IgKGogaW4gMTogbnJvdyhyZTIpKXsKICAgICAgICAgICAgaWYgKHJlMiRzdGFydFtqXTw9cHdzJHN0YXJ0W2ldKzEwMDAwMCAmIHJlMiRzdGFydFtqXT49cHdzJHN0YXJ0W2ldLTEwMDAwMCl7CiAgICAgICAgICAgICAgICBvdmVybHBzPC1yYmluZChvdmVybHBzLCByZTJbaixdKQogICAgICAgICAgICAgICAgb3ZlcmxwczI8LXJiaW5kKG92ZXJscHMyLHB3c1tpLF0pfQogICAgfX0KfSAgICAgIAoKCiNPdmVybGFwcGluZyB3aW5kb3dzOgpvdjwtZGF0YS5mcmFtZShpZD1vdmVybHBzJGlkKQpmb3IgKGkgaW4gMTogbnJvdyhvdmVybHBzKSl7CiAgICBpZiAob3ZlcmxwcyRzdGFydFtpXTxvdmVybHBzMiRzdGFydFtpXSkge292JHN0YXJ0W2ldPC1vdmVybHBzJHN0YXJ0W2ldOyBvdiRlbmRbaV08LW92ZXJscHMyJGVuZFtpXX0KICAgIGlmIChvdmVybHBzJHN0YXJ0W2ldPj1vdmVybHBzMiRzdGFydFtpXSkge292JHN0YXJ0W2ldPC1vdmVybHBzMiRzdGFydFtpXTtvdiRlbmRbaV08LW92ZXJscHMkZW5kW2ldfQp9CndyaXRlLmNzdihvdiwgIi4uL091dHB1dC9DT1YvQ09Wc2Nhbi9PdmVybGFwX3JlZ2lvbnNfQ09WMjNfUFdTLlRCX3BsdXNtaW51czEwMGsuY3N2Iiwgcm93Lm5hbWVzID0gRikKCgojIyMjIENoZWNrIGNocm9tb3NvbWUgcmVnaW9uIG92ZXJsYXAgKy0yMDAsMDAwIGJhc2VzCm92ZXJscHM8LWRhdGEuZnJhbWUoKQpvdmVybHBzMjwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOiBucm93KHB3cykpewogICAgcmUyPC10Ylt0YiRjaHJvbT09cHdzJGNocm9tW2ldLF0KICAgIGlmIChucm93KHJlMik+PTEpewogICAgICAgIGZvciAoaiBpbiAxOiBucm93KHJlMikpewogICAgICAgICAgICBpZiAocmUyJHN0YXJ0W2pdPD1wd3Mkc3RhcnRbaV0rMjAwMDAwICYgcmUyJHN0YXJ0W2pdPj1wd3Mkc3RhcnRbaV0tMjAwMDAwKXsKICAgICAgICAgICAgICAgIG92ZXJscHM8LXJiaW5kKG92ZXJscHMsIHJlMltqLF0pCiAgICAgICAgICAgICAgICBvdmVybHBzMjwtcmJpbmQob3ZlcmxwczIscHdzW2ksXSl9CiAgICB9fQp9ICAgICAgCgojT3ZlcmxhcHBpbmcgd2luZG93czoKb3Y8LWRhdGEuZnJhbWUoaWQ9b3ZlcmxwcyRpZCkKZm9yIChpIGluIDE6IG5yb3cob3ZlcmxwcykpewogICAgaWYgKG92ZXJscHMkc3RhcnRbaV08b3ZlcmxwczIkc3RhcnRbaV0pIHtvdiRzdGFydFtpXTwtb3ZlcmxwcyRzdGFydFtpXTsgb3YkZW5kW2ldPC1vdmVybHBzMiRlbmRbaV19CiAgICBpZiAob3ZlcmxwcyRzdGFydFtpXT49b3ZlcmxwczIkc3RhcnRbaV0pIHtvdiRzdGFydFtpXTwtb3ZlcmxwczIkc3RhcnRbaV07b3YkZW5kW2ldPC1vdmVybHBzJGVuZFtpXX0KfQp3cml0ZS5jc3Yob3YsICIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vT3ZlcmxhcF9yZWdpb25zX0NPVjIzX1BXUy5UQnBsdXNtaW51czIwMGsuY3N2Iiwgcm93Lm5hbWVzID0gRikKCiMjIFBXUyBhbmQgU1MKIyMjIyBDaGVjayBjaHJvbW9zb21lIHJlZ2lvbiBvdmVybGFwICstMjAwLDAwMCBiYXNlcwpvdmVybHBzPC1kYXRhLmZyYW1lKCkKb3ZlcmxwczI8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhwd3MpKXsKICAgIHJlMjwtc3Nbc3MkY2hyb209PXB3cyRjaHJvbVtpXSxdCiAgICBpZiAobnJvdyhyZTIpPj0xKXsKICAgICAgICBmb3IgKGogaW4gMTogbnJvdyhyZTIpKXsKICAgICAgICAgICAgaWYgKHJlMiRzdGFydFtqXTw9cHdzJHN0YXJ0W2ldKzIwMDAwMCAmIHJlMiRzdGFydFtqXT49cHdzJHN0YXJ0W2ldLTIwMDAwMCl7CiAgICAgICAgICAgICAgICBvdmVybHBzPC1yYmluZChvdmVybHBzLCByZTJbaixdKQogICAgICAgICAgICAgICAgb3ZlcmxwczI8LXJiaW5kKG92ZXJscHMyLHB3c1tpLF0pfQogICAgfX0KfSAgICAgIAoKI092ZXJsYXBwaW5nIHdpbmRvd3M6Cm92PC1kYXRhLmZyYW1lKGlkPW92ZXJscHMkaWQpCmZvciAoaSBpbiAxOiBucm93KG92ZXJscHMpKXsKICAgIGlmIChvdmVybHBzJHN0YXJ0W2ldPG92ZXJscHMyJHN0YXJ0W2ldKSB7b3Ykc3RhcnRbaV08LW92ZXJscHMkc3RhcnRbaV07IG92JGVuZFtpXTwtb3ZlcmxwczIkZW5kW2ldfQogICAgaWYgKG92ZXJscHMkc3RhcnRbaV0+PW92ZXJscHMyJHN0YXJ0W2ldKSB7b3Ykc3RhcnRbaV08LW92ZXJscHMyJHN0YXJ0W2ldO292JGVuZFtpXTwtb3ZlcmxwcyRlbmRbaV19Cn0Kd3JpdGUuY3N2KG92LCAiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL092ZXJsYXBfcmVnaW9uc19DT1YyM19QV1MuU1NwbHVzbWludXMyMDBrLmNzdiIsIHJvdy5uYW1lcyA9IEYpCgojIyBTUyBhbmQgVEIKIyMjIyBDaGVjayBjaHJvbW9zb21lIHJlZ2lvbiBvdmVybGFwICstMjAwLDAwMCBiYXNlcwpvdmVybHBzPC1kYXRhLmZyYW1lKCkKb3ZlcmxwczI8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhwd3MpKXsKICAgIHJlMjwtc3Nbc3MkY2hyb209PXRiJGNocm9tW2ldLF0KICAgIGlmIChucm93KHJlMik+PTEpewogICAgICAgIGZvciAoaiBpbiAxOiBucm93KHJlMikpewogICAgICAgICAgICBpZiAocmUyJHN0YXJ0W2pdPD10YiRzdGFydFtpXSsyMDAwMDAgJiByZTIkc3RhcnRbal0+PXRiJHN0YXJ0W2ldLTIwMDAwMCl7CiAgICAgICAgICAgICAgICBvdmVybHBzPC1yYmluZChvdmVybHBzLCByZTJbaixdKQogICAgICAgICAgICAgICAgb3ZlcmxwczI8LXJiaW5kKG92ZXJscHMyLHRiW2ksXSl9CiAgICB9fQp9ICAgICAgCiNPdmVybGFwcGluZyB3aW5kb3dzOgpvdjwtZGF0YS5mcmFtZShpZD1vdmVybHBzJGlkKQpmb3IgKGkgaW4gMTogbnJvdyhvdmVybHBzKSl7CiAgICBpZiAob3ZlcmxwcyRzdGFydFtpXTxvdmVybHBzMiRzdGFydFtpXSkge292JHN0YXJ0W2ldPC1vdmVybHBzJHN0YXJ0W2ldOyBvdiRlbmRbaV08LW92ZXJscHMyJGVuZFtpXX0KICAgIGlmIChvdmVybHBzJHN0YXJ0W2ldPj1vdmVybHBzMiRzdGFydFtpXSkge292JHN0YXJ0W2ldPC1vdmVybHBzMiRzdGFydFtpXTtvdiRlbmRbaV08LW92ZXJscHMkZW5kW2ldfQp9CndyaXRlLmNzdihvdiwgIi4uL091dHB1dC9DT1YvQ09Wc2Nhbi9PdmVybGFwX3JlZ2lvbnNfQ09WMjNfU1MuVEJwbHVzbWludXMyMDBrLmNzdiIsIHJvdy5uYW1lcyA9IEYpCgoKIyMgUFdTLCBTUyBhbmQgVEIKIyMjIyBDaGVjayBjaHJvbW9zb21lIHJlZ2lvbiBvdmVybGFwICstMjAwLDAwMCBiYXNlcwpvdmVybHBwdzwtZGF0YS5mcmFtZSgpCm92ZXJscHNzPC1kYXRhLmZyYW1lKCkKb3ZlcmxwdGI8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhwd3MpKXsKICAgIHJlMjwtc3Nbc3MkY2hyb209PXB3cyRjaHJvbVtpXSxdCiAgICByZTM8LXRiW3RiJGNocm9tPT1wd3MkY2hyb21baV0sXQogICAgCiAgICBpZiAobnJvdyhyZTIpPj0xJiBucm93KHJlMyk+PTEpewogICAgICAgIGZvciAoaiBpbiAxOiBucm93KHJlMikpewogICAgICAgICAgICBpZiAocmUyJHN0YXJ0W2pdPD1wd3Mkc3RhcnRbaV0rMjAwMDAwICYgcmUyJHN0YXJ0W2pdPj1wd3Mkc3RhcnRbaV0tMjAwMDAwKXsKICAgICAgICAgICAgICAgIGZvciAoayBpbiAxOiBucm93KHJlMykpewogICAgICAgICAgICAgICAgICAgIGlmIChyZTMkc3RhcnRba108PXB3cyRzdGFydFtpXSsyMDAwMDAgJiByZTMkc3RhcnRba10+PXB3cyRzdGFydFtpXS0yMDAwMDApewogICAgICAgICAgICAgICAgICAgIG92ZXJscHNzPC1yYmluZChvdmVybHBzcywgcmUyW2osXSkKICAgICAgICAgICAgICAgICAgICBvdmVybHB0YjwtcmJpbmQob3ZlcmxwdGIsIHJlM1trLF0pCiAgICAgICAgICAgICAgICAgICAgb3ZlcmxwcHc8LXJiaW5kKG92ZXJscHB3LHB3c1tpLF0pfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICB9fQp9ICAgICAgCgpvdjwtb3Zlcmxwc3NbLTMsXQpvdiRlbmRbMl08LTI3MDAwMDAwCm92PC1vdlssYygxOjQsNildCm92PC1yYmluZChvdixvdixvdikKb3YkcG9wWzU6OF08LSJQV1MiCm92JHBvcFs5OjEyXTwtIlRCIgpvdiRjb3YyM1s1OjhdPC1vdmVybHBwd1tjKDEsMiw0LDUpLCJjb3YyMyJdCm92JGNvdjIzWzk6MTJdPC1vdmVybHB0YltjKDEsMiw0LDUpLCJjb3YyMyJdCgp3cml0ZS5jc3Yob3ZbLDE6M10sICIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vT3ZlcmxhcF9yZWdpb25zX0NPVjIzXzNQb3BzX3BsdXNtaW51czIwMGsuY3N2Iiwgcm93Lm5hbWVzID0gRikKCnNpbmsoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbi9vdmVybGFwX2NvdjIzXzNwb3AuYmVkIikKY2F0KCJ0cmFjayB0eXBlPWJlZEdyYXBoIFxuIikKb3B0aW9ucyhzY2lwZW49OTk5KQpmb3IgKGkgaW4gMTo0KXsKICAgIGNhdChwYXN0ZTAob3YkY2hyb21baV0sIlx0IixvdiRzdGFydFtpXSwgIlx0Iiwgb3YkZW5kW2ldLCAiXG4iKSkKfQpzaW5rKE5VTEwpCgpwMjNfYW5vPC1yZWFkLnRhYmxlKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vUFdTX291dGxpZXJzX2NvdjIzX2Fubm90YXRpb24iLCBzZXA9IiAiKQpwMjNfYW5vMjwtcmVhZC50YWJsZSgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL1NTX291dGxpZXJzX2NvdjIzX2Fubm90YXRpb24iLCBzZXA9IiAiKQpwMjNfYW5vMzwtcmVhZC50YWJsZSgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL1RCX291dGxpZXJzX2NvdjIzX2Fubm90YXRpb24iLCBzZXA9IiAiKQoKY29tbW9uPC1wMjNfYW5vW3AyM19hbm8kVjEgJWluJSBvdiRjaHJvbSxdCmNvbW1vbjI8LXAyM19hbm8yW3AyM19hbm8yJFYxICVpbiUgb3YkY2hyb20sXQpjb21tb24zPC1wMjNfYW5vM1twMjNfYW5vMyRWMSAlaW4lIG92JGNocm9tLF0KCmNvbW1vbjwtcmJpbmQoY29tbW9uLCBjb21tb24yLCBjb21tb24zKQpjb21tb248LWNvbW1vblshZHVwbGljYXRlZChjb21tb24pLF0KCmdlbmVzPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6NCl7CiAgICBkZjwtY29tbW9uW2NvbW1vbiRWMj49b3Ykc3RhcnRbaV0gJiBjb21tb24kVjI8PW92JGVuZFtpXSAmIGNvbW1vbiRWMT09b3YkY2hyb21baV0sXQogICAgZ2VuZXM8LXJiaW5kKGdlbmVzLGRmKQp9CgojIFBlcnNlIHRoZSBnZW5lIGluZm8KYW5ub3RhdGlvbnM8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhnZW5lcykpewogICAgYW5uczwtdW5saXN0KHN0cnNwbGl0KGdlbmVzJFY0W2ldLCAiXFwsfFxcfCIpKQogICAgYW5ubTwtZGF0YS5mcmFtZShtYXRyaXgoYW5ucyxuY29sID0gMTYsIGJ5cm93ID0gVFJVRSkpCiAgICBhbm5tPC1hbm5tWyxjKDIsMyw0LDUsOCldCiAgICBjb2xuYW1lcyhhbm5tKTwtYygiRWZmZWN0IiwiUHV0YXRpdmVfaW1wYWN0IiwiR2VuZV9uYW1lIiwiR2VuZV9JRCIsIkZlYXR1cmUgdHlwZSIpCiAgICBhbm5tPC1hbm5tWyFkdXBsaWNhdGVkKGFubm0pLCBdCiAgICBhbm5tJGNocjwtZ2VuZXMkVjFbaV0KICAgIGFubm0kcG9zPC1nZW5lcyRWMltpXQogICAgYW5ubSRBRjwtZ2VuZXMkVjNbaV0KICAgIGFubm90YXRpb25zPC1yYmluZChhbm5vdGF0aW9ucywgYW5ubSkKfSAgICAgCmFubm90YXRpb25zIDwtYW5ub3RhdGlvbnNbIWR1cGxpY2F0ZWQoYW5ub3RhdGlvbnMpLCBdCmFubm90YXRpb25zPC1hbm5vdGF0aW9uc1ssYyg2OjgsMTo1KV0KCndyaXRlLmNzdihhbm5vdGF0aW9ucywgIi4uL091dHB1dC9DT1YvQ09Wc2Nhbi9HZW5lc19QV1Nvbmx5X291dGxpZXJzXzEwMGtfY292MTIuY3N2Iiwgcm93Lm5hbWVzID0gRikKYW5ub3RhdGlvbnM8LWNiaW5kKGRmWywxOjJdLCBhbm5vdGF0aW9ucykKY29sbmFtZXMoYW5ub3RhdGlvbnMpPC1jKCJjaHIiLCAicG9zIiwgIkFubm90YXRpb24iLCJQdXRhdGl2ZV9pbXBhY3QiLCJHZW5lX25hbWUiLCAiR2VuZV9JRCIsICJUcmFuc2NyaXB0X2Jpb3R5cGUiLCJBbm5vdGF0aW9uMiIsIlB1dGF0aXZlX2ltcGFjdDIiLCJHZW5lX25hbWUyIiwgIkdlbmVfSUQyIiwgIlRyYW5zY3JpcHRfYmlvdHlwZTIiKQoKCmFubzwtYW5ub3RhdGlvbnNbIShkdXBsaWNhdGVkKGFubm90YXRpb25zWywzOjZdKSksXQpmb2N1czwtYW5vW2FubyRwb3M+PTI2NDI1MDAwJiBhbm8kcG9zPD0yNjQ5MDAwMCxdCndyaXRlLmNzdihmb2N1cywgIi4uL091dHB1dC9QQ0EvZ2VuZXMvQ2hyMjBfZ2VuZXNfaW5fMjYuNC0yNi42TS5jc3YiKQoKCgpgYGAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIyBDaGVjayBjaHJvbW9zb21lIG92ZXJsYXAKCgoKCmBgYAoKCgojIENvbXBhcmUgcmVzdWx0cyBmcm9tIFBXU29ubHkgYW5kIFBILTNwb3BzIFZDRiBmaWxlcwpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwd3MxPC1yZWFkLmNzdigiLi4vT3V0cHV0L0NPVi9QV1Nvbmx5X3RvcDFwZXJjZW50X291dGxpZXJfY292MTJfb3ZlcmxhcC5jc3YiKQpwd3MxPC1wd3MxW3B3czEkd2luZG93PT0iMTAwayIsXQpwd3MyPC1yZWFkLmNzdigiLi4vT3V0cHV0L0NPVi8zcG9wc190b3AxcGVyY2VudF9vdXRsaWVyX3JlZ2lvbnMuY292MTIuY3N2IikKcHdzMjwtcHdzMltwd3MyJHBvcD09IlBXUyImcHdzMiR3aW5kb3c9PSIxMDBrIixdCgpwd3MxJHZjZjwtIlBXU29ubHkiCnB3czIkdmNmPC0iM1BvcHMiCgpwd3M8LXJiaW5kKHB3czFbLGMoImNocm9tIiwic3RhcnQiLCJlbmQiLCJjb3YxMiIsInZjZiIpXSxwd3MyWyxjKCJjaHJvbSIsInN0YXJ0IiwiZW5kIiwiY292MTIiLCJ2Y2YiKV0pCmdncGxvdChkYXRhPXB3cyxhZXMoeD1zdGFydCwgeT1jb3YxMiwgY29sb3I9dmNmLCBmaWxsPXZjZikpKwogICAgZmFjZXRfd3JhcCh+Y2hyb20pKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2d0aXRsZSgiUFdTIENPVjEyIikKZ2dzYXZlKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vUFdTb25seV8zUG9wc19PdXRsaWVyX292ZXJsYXBfY292MTIucG5nIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCwgZHBpPTMwMCkKICAgIApwd3MxPC1yZWFkLmNzdigiLi4vT3V0cHV0L0NPVi9QV1Nvbmx5X3RvcDFwZXJjZW50X291dGxpZXJfY292MjNfb3ZlcmxhcC5jc3YiKQpwd3MxPC1wd3MxW3B3czEkd2luZG93PT0iMTAwayIsXQpwd3MyPC1yZWFkLmNzdigiLi4vT3V0cHV0L0NPVi8zcG9wc190b3AxcGVyY2VudF9vdXRsaWVyX3JlZ2lvbnMuY292MjMuY3N2IikKcHdzMjwtcHdzMltwd3MyJHBvcD09IlBXUyImcHdzMiR3aW5kb3c9PSIxMDBrIixdCgpwd3MxJHZjZjwtIlBXU29ubHkiCnB3czIkdmNmPC0iM1BvcHMiCgpwd3M8LXJiaW5kKHB3czFbLGMoImNocm9tIiwic3RhcnQiLCJlbmQiLCJjb3YyMyIsInZjZiIpXSxwd3MyWyxjKCJjaHJvbSIsInN0YXJ0IiwiZW5kIiwiY292MjMiLCJ2Y2YiKV0pCmdncGxvdChkYXRhPXB3cyxhZXMoeD1zdGFydCwgeT1jb3YyMywgY29sb3I9dmNmLCBmaWxsPXZjZikpKwogICAgZmFjZXRfd3JhcCh+Y2hyb20pKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2d0aXRsZSgiUFdTIENPVjIzIikKZ2dzYXZlKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vUFdTb25seV8zUG9wc19PdXRsaWVyX292ZXJsYXBfY292MjMucG5nIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCwgZHBpPTMwMCkKICAgIApwd3MxPC1yZWFkLmNzdigiLi4vT3V0cHV0L0NPVi9QV1Nvbmx5X3RvcDFwZXJjZW50X291dGxpZXJfY292MTNfb3ZlcmxhcC5jc3YiKQpwd3MxPC1wd3MxW3B3czEkd2luZG93PT0iMTAwayIsXQpwd3MyPC1yZWFkLmNzdigiLi4vT3V0cHV0L0NPVi8zcG9wc190b3AxcGVyY2VudF9vdXRsaWVyX3JlZ2lvbnMuY292MTMuY3N2IikKcHdzMjwtcHdzMltwd3MyJHBvcD09IlBXUyImcHdzMiR3aW5kb3c9PSIxMDBrIixdCgpwd3MxJHZjZjwtIlBXU29ubHkiCnB3czIkdmNmPC0iM1BvcHMiCgpwd3M8LXJiaW5kKHB3czFbLGMoImNocm9tIiwic3RhcnQiLCJlbmQiLCJjb3YxMyIsInZjZiIpXSxwd3MyWyxjKCJjaHJvbSIsInN0YXJ0IiwiZW5kIiwiY292MTMiLCJ2Y2YiKV0pCmdncGxvdChkYXRhPXB3cyxhZXMoeD1zdGFydCwgeT1jb3YxMywgY29sb3I9dmNmLCBmaWxsPXZjZikpKwogICAgZmFjZXRfd3JhcCh+Y2hyb20pKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2d0aXRsZSgiUFdTIENPVjEzIikKZ2dzYXZlKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW4vUFdTb25seV8zUG9wc19PdXRsaWVyX292ZXJsYXBfY292MTMucG5nIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCwgZHBpPTMwMCkKCmBgYAohW10oLi4vT3V0cHV0L0NPVi9DT1ZzY2FuL1BXU29ubHlfM1BvcHNfT3V0bGllcl9vdmVybGFwX2NvdjEyLnBuZykKCiFbXSguLi9PdXRwdXQvQ09WL0NPVnNjYW4vUFdTb25seV8zUG9wc19PdXRsaWVyX292ZXJsYXBfY292MjMucG5nKQoKIVtdKC4uL091dHB1dC9DT1YvQ09Wc2Nhbi9QV1Nvbmx5XzNQb3BzX091dGxpZXJfb3ZlcmxhcF9jb3YxMy5wbmcpCgojIEZpbmQgCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgoKYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpgYGAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmBgYAoK